package com.deimos.sps;

import java.text.ParseException;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.vast.ows.OWSException;
import org.vast.ows.sps.GetFeasibilityResponse;
import org.vast.ows.sps.ReservationReport;
import org.vast.ows.sps.StatusReport;
import org.vast.ows.sps.SubmitRequest;
import org.vast.ows.sps.SubmitResponse;
import org.vast.ows.sps.TaskingResponse;
import org.vast.ows.sps.StatusReport.RequestStatus;
import org.vast.util.DateTime;
import org.w3c.dom.Element;

import com.deimos.Notification;
import com.deimos.UtilsDeimos;
import com.deimos.dataBase.Event;
import com.deimos.dataBase.Segment;
import com.deimos.dataBase.Sensor;
import com.deimos.dataBase.Task;
import com.deimos.dataBase.TaskController;
import com.deimos.sps.GetFeasibility.Operation;
import com.deimos_space.sps_cfi.jni.Planner;
import com.spotimage.eosps.EOReportHelper;
import com.spotimage.eosps.SubmitSegmentByIDRequest;
import com.spotimage.eosps.EOConstants.AcqStatus;
import com.spotimage.eosps.EOConstants.ReportType;

public class SubmitSegmentByID {
    // private SubmitResponse response;
    String task = null;
    SubmitSegmentByIDRequest request = null;
    SubmitRequest submitRequest = null;
    SubmitResponse response = null;
    Set<Segment> segments;
    String validatedS = "";
    Event event = null;
    TaskController taskController = new TaskController();

    public SubmitSegmentByID(SubmitSegmentByIDRequest request) throws ParseException, OWSException {
	this.request = request;
    }

    @SuppressWarnings("unchecked")
    public SubmitResponse getResponse() throws OWSException {
	String id = request.getTaskID();
	StatusReport report = new StatusReport();

	response = new SubmitResponse();

	taskController.validateStatus(id);
	taskController.validateSegments(id);
	event = taskController.getLastEvent(id);
	if (event == null)
	    throw new OWSException(OWSException.invalid_param_code, "task", request.getTaskID(), request.getTaskID() + " task not found into the database");

	report.setRequestStatus(event.getRequestStatus());
	report.setTaskStatus(event.getTaskStatus());
	report.setTaskID(Planner.getNewFeasibilityId());
	report.setDescription(event.getDescription());
	try {
	    Iterator it = UtilsDeimos.readParams(event.getResponseParameters()).getReport().getExtensions().entrySet().iterator();
	    while (it.hasNext()) {
		Map.Entry e = (Map.Entry) it.next();
		report.addExtension((Element) e.getValue());
	    }
	} catch (Exception e) {
	    e.printStackTrace();
	}
	if (event.getTask().getDelay() != null)
	    report.setEstimatedDelay(event.getTask().getDelay().intValue());
	if (event.getEstimatedToC() != null)
	    report.setEstimatedToC(new DateTime(event.getEstimatedToC().getTime()));
	if (event.getUpdateDate() != null)
	    report.setLastUpdate(new DateTime());
	report.setTitle(event.getTask().getTitle());
	report.setSensorID(event.getTask().getSensorId());

	response.setService("SPS");
	response.setVersion("2.0.0");

	onlyAcquired(report, Operation.SUBMITTED, new Sensor(event.getTask().getSensorId()), request.getSegmentIDs());

	response.setReport(report);
	return response;
    }

    public void addTask(SubmitResponse response) {
	Task task = new Task();
	Event event = new Event();
	StatusReport report = response.getReport();
	task.setSensorId(this.event.getTask().getSensorId());
	task.setServiceType(response.getService());
	task.setTaskId(report.getTaskID());
	task.setTitle(report.getTitle());

	event.setRequestStatus(report.getRequestStatus());
	event.setTaskStatus(report.getTaskStatus());
	event.setDescription(report.getDescription());
	event.setUpdateDate(new Date());
	event.setEstimatedToC(report.getEstimatedToC());
	event.setResponseParameters(UtilsDeimos.getParameters(response));
	event.setRequestParameters(this.event.getRequestParameters().replace("GetFeasibilityRequest", "SubmitRequest"));
	event.setFeasibilityStudy(report != null && report.getRequestStatus() == RequestStatus.Accepted);
	event.setBeginDate(this.event.getBeginDate());
	event.setEndDate(this.event.getEndDate());
	event.setMaxCloud(this.event.getMaxCloud());
	event.setOperation(Operation.SUBMITTED);

	task.addEvent(event);
	task.setSegments(segments);

	taskController.insertTask(task);
	event.setTask(task);
	Notification.notifyReport(event);
    }

    @SuppressWarnings("unchecked")
    public void onlyAcquired(StatusReport report, Operation operation, Sensor sensor, List<String> segmentIds) throws OWSException {
	try {
	    segments = new HashSet<Segment>();
	    TaskingResponse response = new GetFeasibilityResponse();
	    EOReportHelper eohelper = new EOReportHelper(report);
	    EOReportHelper neweohelper;
	    report.getExtensions().clear();
	    response.setReport(new ReservationReport());
	    if (Operation.STUDIED == operation || !sensor.isSyn())
		neweohelper = new EOReportHelper(response, ReportType.FEASIBILITY);
	    else
		neweohelper = new EOReportHelper(response, ReportType.PROG_STATUS);
	    if (Operation.STUDIED == operation || !sensor.isSyn())
		neweohelper.setEstimatedCost(eohelper.getEstimatedCost());
	    if (Operation.STUDIED == operation || !sensor.isSyn())
		for (int j = 0; j < eohelper.getInformationUsed().size(); j++)
		    neweohelper.addInformationUsed(eohelper.getInformationUsed().get(j));
	    // neweohelper.setExpirationDelay(eohelper.ge());
	    if (Operation.STUDIED == operation || !sensor.isSyn())
		neweohelper.setOverallSuccessRate(eohelper.getOverallSuccessRate());
	    if (Operation.STUDIED == operation || !sensor.isSyn())
		neweohelper.setExpirationDate(eohelper.getExpirationDate());
	    boolean inUse = false;
	    for (String seg : segmentIds) {
		boolean encontrado = false;
		for (int i = 0; i < eohelper.getNumSegments(); i++) {
		    eohelper.loadSegment(i);
		    if (seg.compareTo(eohelper.getID()) == 0) {
			List<String> tasks = taskController.isSensorInUse(event.getTask().getSensorId(), (Date) eohelper.getAcquisitionStart(), (Date) eohelper.getAcquisitionStop(), null);
			if (tasks != null && tasks.size() != 0) {
			    String desc = "Task not feasible. The sensor " + event.getTask().getSensorId() + " is in use by the ";
			    if (tasks.size() > 1)
				desc = desc + "tasks: ";
			    else
				desc = desc + "task: ";
			    for (String task : tasks)
				desc = desc + task + ", ";
			    desc = (desc + ".").replace(", .", ". ");
			    report.setDescription(desc);
			    report.setRequestStatus(RequestStatus.Rejected);

			    inUse = true;
			    eohelper.setNumSegments(0);
			}
			encontrado = true;
		    }
		}
		if (!encontrado) 
		    throw new OWSException(OWSException.invalid_param_code, "segmentID", seg, seg + " segmentID not found into the database");
	    }

	    for (int i = 0; i < eohelper.getNumSegments() && !inUse; i++) {
		eohelper.loadSegment(i);
		if (findSegment(eohelper.getID(), segmentIds)) {
		    neweohelper.addSegment();
		    neweohelper.loadSegment(neweohelper.getNumSegments() - 1);
		    neweohelper.setID(eohelper.getID());
		    neweohelper.setObjectStatus(AcqStatus.PLANNED);
		    neweohelper.setPlatformID(eohelper.getPlatformID());
		    neweohelper.setPlatformName(eohelper.getPlatformName());
		    neweohelper.setInstrumentName(eohelper.getInstrumentName());
		    neweohelper.setInstrumentMode(eohelper.getInstrumentMode());
		    if (Operation.STUDIED == operation || !sensor.isSyn())
			neweohelper.setExpirationDate(eohelper.getExpirationDate());
		    neweohelper.setAcquisitionStart(eohelper.getAcquisitionStart());
		    neweohelper.setAcquisitionStop(eohelper.getAcquisitionStop());
		    neweohelper.setFootprint(eohelper.getFootprint());
		    neweohelper.setNumGridCells(eohelper.getNumGridCells());
		    Segment segment = new Segment();
		    segment.setName(eohelper.getID());
		    segment.setBeginDate(eohelper.getAcquisitionStart());
		    segment.setEndDate(eohelper.getAcquisitionStop());
		    segment.setUpdateDate(new Date());
		    segment.setSensor(sensor.getSensorId());
		    segment.setAcqStatus(eohelper.getObjectStatus());
		    segments.add(segment);
		}
	    }

	    neweohelper.writeReportInfo();
	    response.getReport().touch();
	    report.getExtensions().clear();
	    if (!inUse)
		report.getExtensions().putAll(response.getReport().getExtensions());
	} catch (Exception e) {
	    if (e instanceof OWSException)
		throw (OWSException) e;
	}
    }

    public boolean findSegment(String id, List<String> segments) {
	for (String segment : segments) {
	    if (segment.compareTo(id) == 0)
		return true;
	}
	return false;
    }

}
